import { ref, computed, onMounted, onBeforeUnmount, nextTick, type Ref } from 'vue';

export interface UseComboboxOptions<T> {
  items: Ref<T[]> | T[];
  toText?: (item: T) => string;
}

export function useCombobox<T = string>(options: UseComboboxOptions<T>) {
  const itemsRef = Array.isArray(options.items) ? ref(options.items) : options.items;
  const toText = options.toText || ((x: T) => String(x ?? ''));

  const open = ref(false);
  const query = ref('');
  const highlightIndex = ref(-1);

  const filteredItems = computed(() => {
    const q = query.value.trim().toLowerCase();
    const items = itemsRef.value as T[];
    if (!q) return items || [];
    return (items || []).filter((it) => toText(it).toLowerCase().includes(q));
  });

  function openMenu() {
    open.value = true;
    highlightIndex.value = filteredItems.value.length ? 0 : -1;
    nextTick(() => {
      const el = document.querySelector('[data-combobox-search="1"]') as HTMLInputElement | null;
      if (el) el.focus();
    });
  }

  function closeMenu() {
    open.value = false;
    highlightIndex.value = -1;
  }

  function onKeyNav(e: KeyboardEvent, onChoose: (item: T) => void) {
    if (!open.value) return;
    if (e.key === 'ArrowDown') {
      e.preventDefault();
      if (!filteredItems.value.length) return;
      highlightIndex.value = (highlightIndex.value + 1) % filteredItems.value.length;
    } else if (e.key === 'ArrowUp') {
      e.preventDefault();
      if (!filteredItems.value.length) return;
      highlightIndex.value = (highlightIndex.value - 1 + filteredItems.value.length) % filteredItems.value.length;
    } else if (e.key === 'Enter') {
      e.preventDefault();
      const it = filteredItems.value[highlightIndex.value] as T;
      if (it != null) onChoose(it);
    } else if (e.key === 'Escape') {
      e.preventDefault();
      closeMenu();
    }
  }

  return {
    // state
    open,
    query,
    highlightIndex,
    filteredItems,
    // actions
    openMenu,
    closeMenu,
    onKeyNav,
  };
}